package com.xncoding.wechat.service;

import com.xncoding.wechat.dto.BankCardElement;
import com.xncoding.wechat.dto.FsBankCardRedirectInput;
import com.xncoding.wechat.utils.CryptoUtil;
import com.xncoding.wechat.utils.SignatureUtil;
import com.xncoding.wechat.utils.WXPayUtility;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;


import java.security.PublicKey;
import java.security.PrivateKey;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

//@Service
public class BankCardService {

    @Value("${wechat.appkey}")
    private String appKey;

    @Value("${wechat.crypto.key}")
    private String cryptoKey;

    @Value("${wechat.redirect.url}")
    private String redirectUrl;

    @Autowired
    private SignatureUtil signatureUtil;

    @Autowired
    private CryptoUtil cryptoUtil;
    private String appId;
    private PublicKey publicKey;  // 银行公钥，用于加密银行要素
    private PrivateKey privateKey; // 商户私钥，用于其他签名（如需要）

    public BankCardService(String appId, String appKey, PublicKey publicKey) {
        this.appId = appId;
        this.appKey = appKey;
        this.publicKey = publicKey;
    }

    public BankCardService(String appId, String appKey, PublicKey publicKey, PrivateKey privateKey) {
        this.appId = appId;
        this.appKey = appKey;
        this.publicKey = publicKey;
        this.privateKey = privateKey;
    }
    /**
     * 验证请求参数并生成跳转URL
     */
    public String generateRedirectUrl(FsBankCardRedirectInput request) throws Exception {
        // 1. 验证签名
        if (!verifySignature(request)) {
            throw new RuntimeException("签名验证失败");
        }

        // 2. 解密银行要素块
        BankCardElement element = cryptoUtil.decryptBankElement(request.getEncBankelem(), cryptoKey);

        // 3. 验证业务逻辑（根据实际需求实现）
        validateBusinessLogic(element, request.getOpenid());

        // 4. 构建跳转参数
        Map<String, String> params = buildRedirectParams(request);

        // 5. 生成完整跳转URL
        return redirectUrl + "?" + signatureUtil.buildRedirectUrlParams(params);
    }

    /**
     * 验证签名
     */
    private boolean verifySignature(FsBankCardRedirectInput request) {
        Map<String, String> signParams = new HashMap<>();
        signParams.put("appid", request.getAppid());
        signParams.put("bind_tail", request.getBindTail());
        signParams.put("enc_bankelem", request.getEncBankelem());
        signParams.put("noncestr", request.getNoncestr());
        signParams.put("openid", request.getOpenid());
        signParams.put("sessionid", request.getSessionid());
        signParams.put("timestamp", request.getTimestamp());

        return signatureUtil.verifySignature(signParams, appKey, request.getPaysign());
    }

    /**
     * 验证业务逻辑
     */
    private void validateBusinessLogic(BankCardElement element, String openid) {
        // 这里实现具体的业务验证逻辑
        // 1. 验证证件信息与真实姓名的一致性
        if (!validateIdCard(element.getCreId(), element.getTrueName())) {
            throw new RuntimeException("证件信息与真实姓名不匹配");
        }

        // 2. 验证OpenID的有效性（需要与小程序侧OpenID一致）
        if (!validateOpenId(openid)) {
            throw new RuntimeException("OpenID验证失败");
        }

        // 3. 其他业务验证...
    }

    /**
     * 构建跳转参数
     */
    private Map<String, String> buildRedirectParams(FsBankCardRedirectInput request) {
        Map<String, String> params = new HashMap<>();
        params.put("appid", request.getAppid());
        params.put("bind_tail", request.getBindTail());
        params.put("enc_bankelem", request.getEncBankelem());
        params.put("noncestr", request.getNoncestr());
        params.put("openid", request.getOpenid());
        params.put("sessionid", request.getSessionid());
        params.put("timestamp", request.getTimestamp());
        params.put("signtype", request.getSigntype());
        params.put("paysign", request.getPaysign());
        return params;
    }

    /**
     * 模拟验证证件信息（实际需要调用公安系统验证）
     */
    private boolean validateIdCard(String creId, String trueName) {
        // 这里实现证件验证逻辑
        // 实际项目中需要调用公安系统或第三方验证服务
        return true; // 模拟验证通过
    }

    /**
     * 验证OpenID有效性
     */
    private boolean validateOpenId(String openid) {
        // 这里实现OpenID验证逻辑
        // 需要与小程序侧的OpenID进行比对
        return true; // 模拟验证通过
    }

    /**
     * 生成银行要素块密文（供测试使用）
     */
    public String generateBankElementEncrypted(BankCardElement element) throws Exception {
        return cryptoUtil.encryptBankElement(element, cryptoKey);
    }

    /**
     * 生成签名（供测试使用）
     */
    public String generateTestSignature(Map<String, String> params) {
        return signatureUtil.generateSHA1Sign(params, appKey);
    }

    //--------------------
    /**
     * 生成跳转银行页面的URL
     */
    public String generateBankRedirectUrl(FsBankCardRedirectInput request, String basePath) {
        // 1. 设置基本参数
        request.setAppid(appId);
        request.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000));
        request.setNoncestr(WXPayUtility.createNonce(32));

        // 2. 生成签名
        String sign = generateSignature(request);
        request.setPaysign(sign);

        // 3. 构建跳转URL
        return buildRedirectUrl(request, basePath);
    }

    /**
     * 生成SHA1签名
     */
    private String generateSignature(FsBankCardRedirectInput request) {
        try {
            // 按照字母顺序排列参数
            Map<String, String> params = new TreeMap<>();
            params.put("appid", request.getAppid());
            params.put("bind_tail", request.getBindTail());
            params.put("enc_bankelem", request.getEncBankelem());
            params.put("noncestr", request.getNoncestr());
            params.put("openid", request.getOpenid());
            params.put("sessionid", request.getSessionid());
            params.put("timestamp", request.getTimestamp());

            // 构建签名字符串
            StringBuilder signStr = new StringBuilder();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                if (signStr.length() > 0) {
                    signStr.append("&");
                }
                signStr.append(entry.getKey()).append("=").append(entry.getValue());
            }

            // 添加appkey
            signStr.append("&appkey=").append(appKey);

            // SHA1签名
//            return WXPayUtility.sha1(signStr.toString().getBytes("UTF-8"));
            return null;

        } catch (Exception e) {
            throw new RuntimeException("生成签名失败", e);
        }
    }

    /**
     * 构建跳转URL
     */
    private String buildRedirectUrl(FsBankCardRedirectInput request, String basePath) {
        StringBuilder url = new StringBuilder(basePath);
        url.append("?appid=").append(request.getAppid())
                .append("&bind_tail=").append(request.getBindTail())
                .append("&enc_bankelem=").append(request.getEncBankelem())
                .append("&noncestr=").append(request.getNoncestr())
                .append("&openid=").append(request.getOpenid())
                .append("&sessionid=").append(request.getSessionid())
                .append("&timestamp=").append(request.getTimestamp())
                .append("&signtype=").append(request.getSigntype())
                .append("&paysign=").append(request.getPaysign());

        return url.toString();
    }

    /**
     * 加密银行要素
     */
    public String encryptBankElement(BankCardElement bankElement) {
        try {
            String plainText = bankElement.toParamString();
            return WXPayUtility.encrypt(publicKey, plainText);
        } catch (Exception e) {
            throw new RuntimeException("加密银行要素失败", e);
        }
    }

    /**
     * 编码银行卡尾号（Base64编码，逗号分隔）
     */
    public String encodeBindTail(String[] cardTails) {
        if (cardTails == null || cardTails.length == 0) {
            throw new IllegalArgumentException("银行卡尾号不能为空");
        }

        String tailStr = String.join(",", cardTails);
        return Base64.getEncoder().encodeToString(tailStr.getBytes());
    }

    /**
     * 验证银行返回的签名
     */
    public boolean verifyBankResponse(String signature, Map<String, String> params) {
        try {
            // 构建验签字符串
            Map<String, String> sortedParams = new TreeMap<>(params);
            StringBuilder verifyStr = new StringBuilder();

            for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
                if (verifyStr.length() > 0) {
                    verifyStr.append("&");
                }
                verifyStr.append(entry.getKey()).append("=").append(entry.getValue());
            }

            // 这里需要根据银行提供的公钥进行验签
            // 实际实现需要根据银行的具体要求
            return true;

        } catch (Exception e) {
            throw new RuntimeException("验证签名失败", e);
        }
    }
}
